﻿using HBase;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace hCommand {
    public abstract class LocSelection {
        private const int MAX_WEIGHT = 100000000;

        public CoreWhLoc changeLocSelect<CS>(Sw sw,int src,CS cs,List<long> skipSrcList = null) where CS : AbsCoreStock {
            var whLoc = sw.getById<CoreWhLoc>(src);
            if (whLoc == null) {
                throw new Exception(cs.boxCode + "不在库存");
            }
            List<CoreWhLoc> locList = getLoc4SelectIn(sw,whLoc.areaId,whLoc.moveGroup);
            if (skipSrcList != null && locList.Count > 0) {
                for (int i = 0;i < locList.Count;i++) {
                    if (skipSrcList.Contains(locList[i].scr)) {
                        locList.RemoveAt(i);
                        i--;
                    }
                }
            }
            CoreWhLoc des = select(locList,cs.deepDiff,cs);//每个moveGroup 必须有一个空货位共移库
            return des;

        }
         public CoreWhLoc selectLoc<CS>(Sw sw,CS cs) where CS : AbsCoreStock {
            long itemClassifyId = cs.classifyId;
            if (itemClassifyId == 0) {
                throw new Exception(cs.id + "的分类未找到");
            }
           
            CoreWhLoc beforeLoc = locBeforeSelect(sw,itemClassifyId,cs.deepDiff);
            if (beforeLoc != null) {
                return beforeLoc;
            }
            //一个物料类别对应多个区域
            CoreWhLoc loc = getBastCoreWhLoc(sw,cs);
            return loc;
        }
        protected abstract CoreWhLoc select<CS>(List<CoreWhLoc> locList,long goodDiff,CS cs) where CS : AbsCoreStock;
       
        protected virtual CoreWhLoc getBastCoreWhLoc<CS>(Sw sw,CS cs) where CS : AbsCoreStock {
            AreaLocWeightDto dto = null;
            string sql = @"select * from core_classify_Area  where classify_Id=@classifyId and eigen=@eigen order by Priority ";
            //一个物料类别对应多个区域 查询物料优先放在哪个区域
            List<CoreClassifyArea> coreClassifyAreaList = sw.query<CoreClassifyArea>(sql,cs);
            for (int j = 0;j < coreClassifyAreaList.Count;j++) {
                CoreClassifyArea areaDto = coreClassifyAreaList[j];
                AreaLocWeightDto tmp = getAreaLoc(sw,areaDto,cs); 
                if (tmp == null) {
                    continue;
                }
                if (tmp.weight == MAX_WEIGHT && tmp.loc != null) {//起到优化作用，减少无意义循环
                    return tmp.loc;
                }
                if (dto == null || tmp.weight > dto.weight) {
                    dto = tmp;
                }
            }
            if (dto == null ) {
                return null;
            } 
            return dto.loc;
        }

      protected virtual   AreaLocWeightDto getAreaLoc<CS>(Sw sw,CoreClassifyArea areaDto,CS cs) where CS : AbsCoreStock {
            List<CoreWhLoc> locList = getLoc4SelectIn(sw,areaDto.areaId,0);
            if (locList.Count == 0) {
                CoreWhArea area = sw.getById<CoreWhArea>(areaDto.areaId);
                if (area != null) {
                    LoggerCommon.consol(InfoCode.consle_loc_full,areaDto.id + area.AreaName + "无可用货位");
                } else {
                    LoggerCommon.consol(InfoCode.consle_loc_full,areaDto.areaId + "无库区");
                }
                return null;
            }
            AreaLocWeightDto tmp = getAreaLocWeightDto(sw,areaDto.priority,locList,cs);
            return tmp;

        }
        protected virtual CoreWhLoc locBeforeSelect(Sw sw,long itemClassifyId,long group) {
            return null;
        }


        protected virtual bool full(Sw sw,List<CoreWhLoc> locList) {
            int count = 0;
            int relse = 0;
            foreach (CoreWhLoc loc in locList) {
                if (loc.type != 1) {
                    count++;
                }
                if (loc.countStock < loc.maxStock) {
                    relse++;
                }
            }
            return count > 0 && relse <= 1;
        }
        protected virtual AreaLocWeightDto getAreaLocWeightDto<CS>(Sw sw,int priority,List<CoreWhLoc> alllocList,CS cs) where CS : AbsCoreStock {
            Dictionary<long,List<CoreWhLoc>> coreWhLocDict = groupLoc(sw,alllocList);
            long goodDiff = cs.deepDiff;
            AreaLocWeightDto max =  new AreaLocWeightDto();
            foreach (var item in coreWhLocDict) {
                List<CoreWhLoc> locList = item.Value;
                if (full(sw,locList)) {
                    continue;
                } 
                CoreWhLoc loc = select(locList,goodDiff,cs);
                int weight=getWeight( priority, locList); 
                if (loc == null) {
                    continue;
                }
                if (weight == MAX_WEIGHT) {
                    max.loc = loc;  
                    max.weight = weight;
                    return max;
                }
                if (max.loc == null) {
                    max.loc = loc;  
                    max.weight = weight;
                } else if (weight > max.weight) {
                    max.loc = loc;  
                    max.weight = weight;
                }
            }
            return max;
        }


         protected virtual int getWeight(int priority,List<CoreWhLoc> locList){ 
             if (priority == 1) {
                   return  MAX_WEIGHT;  
                } else if (priority == 2) {
                   return  locList.Count();
                } else if (priority == 3) {
                    float count = 0;
                    foreach (CoreWhLoc loc in locList) {
                        count += loc.countStock;
                    }
                   return (int)((1 - count / locList.Count()) * MAX_WEIGHT);
                   
                }
            return 0;
        }



        protected Dictionary<long,List<CoreWhLoc>> groupLoc(Sw sw,List<CoreWhLoc> locList) {
            Dictionary<long,List<CoreWhLoc>> coreWhLocDict = new Dictionary<long,List<CoreWhLoc>>();
            foreach (CoreWhLoc coreWhLoc in locList) {
                if (coreWhLocDict.ContainsKey(coreWhLoc.moveGroup)) {
                    coreWhLocDict[coreWhLoc.moveGroup].Add(coreWhLoc);
                } else {
                    coreWhLocDict.Add(coreWhLoc.moveGroup,new List<CoreWhLoc>() { coreWhLoc });
                }
            }
            return coreWhLocDict;
        }




        virtual public List<CoreWhLoc> getLoc4SelectIn(Sw sw,long areaId,long moveGroup) {
            string sql = "select l.* from Core_Wh_Loc l where  l.Active_Status in (0,2) and  wcs_Auto_active =1 ";
            if (areaId != -1) {
                sql += " and   l.area_Id = @areaId  ";
            }
            if (moveGroup != 0) {
                sql += " and   l.move_Group=@moveGroup  ";
            }
            sql += i18nSql(sw);
            List<CoreWhLoc> locList = sw.query<CoreWhLoc>(sql,new { areaId,moveGroup });
            return locList;
        }

        public virtual String i18nSql(Sw sw) {
            return "order by order_No";
        }

    }
}
